// Copyright (c) Lawrence Livermore National Security, LLC and other VisIt
// Project developers.  See the top-level LICENSE file for dates and other
// details.  No copyright assignment is required to contribute to VisIt.

#include <MachineProfile.h>
#include <DataNode.h>
#include <Utility.h>
#include <LaunchProfile.h>

//
// Enum conversion methods for MachineProfile::ClientHostDetermination
//

static const char *ClientHostDetermination_strings[] = {
"MachineName", "ManuallySpecified", "ParsedFromSSHCLIENT"
};

std::string
MachineProfile::ClientHostDetermination_ToString(MachineProfile::ClientHostDetermination t)
{
    int index = int(t);
    if(index < 0 || index >= 3) index = 0;
    return ClientHostDetermination_strings[index];
}

std::string
MachineProfile::ClientHostDetermination_ToString(int t)
{
    int index = (t < 0 || t >= 3) ? 0 : t;
    return ClientHostDetermination_strings[index];
}

bool
MachineProfile::ClientHostDetermination_FromString(const std::string &s, MachineProfile::ClientHostDetermination &val)
{
    val = MachineProfile::MachineName;
    for(int i = 0; i < 3; ++i)
    {
        if(s == ClientHostDetermination_strings[i])
        {
            val = (ClientHostDetermination)i;
            return true;
        }
    }
    return false;
}

// ****************************************************************************
// Method: MachineProfile::MachineProfile
//
// Purpose:
//   Init utility for the MachineProfile class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

void MachineProfile::Init()
{
    host = "localhost";
    userName = defaultUserName;
    shareOneBatchJob = false;
    sshPortSpecified = false;
    sshPort = 22;
    sshCommandSpecified = false;
    sshCommand.push_back("ssh");
    useGateway = false;
    clientHostDetermination = MachineName;
    tunnelSSH = false;
    maximumNodesValid = false;
    maximumNodes = 1;
    maximumProcessorsValid = false;
    maximumProcessors = 1;
    activeProfile = -1;

    MachineProfile::SelectAll();
}

// ****************************************************************************
// Method: MachineProfile::MachineProfile
//
// Purpose:
//   Copy utility for the MachineProfile class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

void MachineProfile::Copy(const MachineProfile &obj)
{
    AttributeGroupVector::const_iterator pos;

    host = obj.host;
    userName = obj.userName;
    password = obj.password;
    hostAliases = obj.hostAliases;
    hostNickname = obj.hostNickname;
    directory = obj.directory;
    shareOneBatchJob = obj.shareOneBatchJob;
    sshPortSpecified = obj.sshPortSpecified;
    sshPort = obj.sshPort;
    sshCommandSpecified = obj.sshCommandSpecified;
    sshCommand = obj.sshCommand;
    useGateway = obj.useGateway;
    gatewayHost = obj.gatewayHost;
    clientHostDetermination = obj.clientHostDetermination;
    manualClientHostName = obj.manualClientHostName;
    tunnelSSH = obj.tunnelSSH;
    maximumNodesValid = obj.maximumNodesValid;
    maximumNodes = obj.maximumNodes;
    maximumProcessorsValid = obj.maximumProcessorsValid;
    maximumProcessors = obj.maximumProcessors;
    // *** Copy the launchProfiles field ***
    // Delete the AttributeGroup objects and clear the vector.
    for(pos = launchProfiles.begin(); pos != launchProfiles.end(); ++pos)
        delete *pos;
    launchProfiles.clear();
    if(obj.launchProfiles.size() > 0)
        launchProfiles.reserve(obj.launchProfiles.size());
    // Duplicate the launchProfiles from obj.
    for(pos = obj.launchProfiles.begin(); pos != obj.launchProfiles.end(); ++pos)
    {
        LaunchProfile *oldLaunchProfile = (LaunchProfile *)(*pos);
        LaunchProfile *newLaunchProfile = new LaunchProfile(*oldLaunchProfile);
        launchProfiles.push_back(newLaunchProfile);
    }

    activeProfile = obj.activeProfile;

    MachineProfile::SelectAll();
}

// Type map format string
const char *MachineProfile::TypeMapFormatString = MACHINEPROFILE_TMFS;
const AttributeGroup::private_tmfs_t MachineProfile::TmfsStruct = {MACHINEPROFILE_TMFS};


// ****************************************************************************
// Method: MachineProfile::MachineProfile
//
// Purpose:
//   Default constructor for the MachineProfile class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

MachineProfile::MachineProfile() :
    AttributeSubject(MachineProfile::TypeMapFormatString)
{
    MachineProfile::Init();
}

// ****************************************************************************
// Method: MachineProfile::MachineProfile
//
// Purpose:
//   Constructor for the derived classes of MachineProfile class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

MachineProfile::MachineProfile(private_tmfs_t tmfs) :
    AttributeSubject(tmfs.tmfs)
{
    MachineProfile::Init();
}

// ****************************************************************************
// Method: MachineProfile::MachineProfile
//
// Purpose:
//   Copy constructor for the MachineProfile class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

MachineProfile::MachineProfile(const MachineProfile &obj) :
    AttributeSubject(MachineProfile::TypeMapFormatString)
{
    MachineProfile::Copy(obj);
}

// ****************************************************************************
// Method: MachineProfile::MachineProfile
//
// Purpose:
//   Copy constructor for derived classes of the MachineProfile class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

MachineProfile::MachineProfile(const MachineProfile &obj, private_tmfs_t tmfs) :
    AttributeSubject(tmfs.tmfs)
{
    MachineProfile::Copy(obj);
}

// ****************************************************************************
// Method: MachineProfile::~MachineProfile
//
// Purpose:
//   Destructor for the MachineProfile class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

MachineProfile::~MachineProfile()
{
    AttributeGroupVector::iterator pos;

    // Destroy the launchProfiles field.
    for(pos = launchProfiles.begin(); pos != launchProfiles.end(); ++pos)
        delete *pos;
}

// ****************************************************************************
// Method: MachineProfile::operator =
//
// Purpose:
//   Assignment operator for the MachineProfile class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

MachineProfile&
MachineProfile::operator = (const MachineProfile &obj)
{
    if (this == &obj) return *this;

    MachineProfile::Copy(obj);

    return *this;
}

// ****************************************************************************
// Method: MachineProfile::operator ==
//
// Purpose:
//   Comparison operator == for the MachineProfile class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

bool
MachineProfile::operator == (const MachineProfile &obj) const
{
    bool launchProfiles_equal = (obj.launchProfiles.size() == launchProfiles.size());
    for(size_t i = 0; (i < launchProfiles.size()) && launchProfiles_equal; ++i)
    {
        // Make references to LaunchProfile from AttributeGroup *.
        const LaunchProfile &launchProfiles1 = *((const LaunchProfile *)(launchProfiles[i]));
        const LaunchProfile &launchProfiles2 = *((const LaunchProfile *)(obj.launchProfiles[i]));
        launchProfiles_equal = (launchProfiles1 == launchProfiles2);
    }

    // Create the return value
    return ((host == obj.host) &&
            (userName == obj.userName) &&
            (password == obj.password) &&
            (hostAliases == obj.hostAliases) &&
            (hostNickname == obj.hostNickname) &&
            (directory == obj.directory) &&
            (shareOneBatchJob == obj.shareOneBatchJob) &&
            (sshPortSpecified == obj.sshPortSpecified) &&
            (sshPort == obj.sshPort) &&
            (sshCommandSpecified == obj.sshCommandSpecified) &&
            (sshCommand == obj.sshCommand) &&
            (useGateway == obj.useGateway) &&
            (gatewayHost == obj.gatewayHost) &&
            (clientHostDetermination == obj.clientHostDetermination) &&
            (manualClientHostName == obj.manualClientHostName) &&
            (tunnelSSH == obj.tunnelSSH) &&
            (maximumNodesValid == obj.maximumNodesValid) &&
            (maximumNodes == obj.maximumNodes) &&
            (maximumProcessorsValid == obj.maximumProcessorsValid) &&
            (maximumProcessors == obj.maximumProcessors) &&
            launchProfiles_equal &&
            (activeProfile == obj.activeProfile));
}

// ****************************************************************************
// Method: MachineProfile::operator !=
//
// Purpose:
//   Comparison operator != for the MachineProfile class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

bool
MachineProfile::operator != (const MachineProfile &obj) const
{
    return !(this->operator == (obj));
}

// ****************************************************************************
// Method: MachineProfile::TypeName
//
// Purpose:
//   Type name method for the MachineProfile class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

const std::string
MachineProfile::TypeName() const
{
    return "MachineProfile";
}

// ****************************************************************************
// Method: MachineProfile::CopyAttributes
//
// Purpose:
//   CopyAttributes method for the MachineProfile class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

bool
MachineProfile::CopyAttributes(const AttributeGroup *atts)
{
    if(TypeName() != atts->TypeName())
        return false;

    // Call assignment operator.
    const MachineProfile *tmp = (const MachineProfile *)atts;
    *this = *tmp;

    return true;
}

// ****************************************************************************
// Method: MachineProfile::CreateCompatible
//
// Purpose:
//   CreateCompatible method for the MachineProfile class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

AttributeSubject *
MachineProfile::CreateCompatible(const std::string &tname) const
{
    AttributeSubject *retval = 0;
    if(TypeName() == tname)
        retval = new MachineProfile(*this);
    // Other cases could go here too.

    return retval;
}

// ****************************************************************************
// Method: MachineProfile::NewInstance
//
// Purpose:
//   NewInstance method for the MachineProfile class.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

AttributeSubject *
MachineProfile::NewInstance(bool copy) const
{
    AttributeSubject *retval = 0;
    if(copy)
        retval = new MachineProfile(*this);
    else
        retval = new MachineProfile;

    return retval;
}

// ****************************************************************************
// Method: MachineProfile::SelectAll
//
// Purpose:
//   Selects all attributes.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

void
MachineProfile::SelectAll()
{
    Select(ID_host,                    (void *)&host);
    Select(ID_userName,                (void *)&userName);
    Select(ID_password,                (void *)&password);
    Select(ID_hostAliases,             (void *)&hostAliases);
    Select(ID_hostNickname,            (void *)&hostNickname);
    Select(ID_directory,               (void *)&directory);
    Select(ID_shareOneBatchJob,        (void *)&shareOneBatchJob);
    Select(ID_sshPortSpecified,        (void *)&sshPortSpecified);
    Select(ID_sshPort,                 (void *)&sshPort);
    Select(ID_sshCommandSpecified,     (void *)&sshCommandSpecified);
    Select(ID_sshCommand,              (void *)&sshCommand);
    Select(ID_useGateway,              (void *)&useGateway);
    Select(ID_gatewayHost,             (void *)&gatewayHost);
    Select(ID_clientHostDetermination, (void *)&clientHostDetermination);
    Select(ID_manualClientHostName,    (void *)&manualClientHostName);
    Select(ID_tunnelSSH,               (void *)&tunnelSSH);
    Select(ID_maximumNodesValid,       (void *)&maximumNodesValid);
    Select(ID_maximumNodes,            (void *)&maximumNodes);
    Select(ID_maximumProcessorsValid,  (void *)&maximumProcessorsValid);
    Select(ID_maximumProcessors,       (void *)&maximumProcessors);
    Select(ID_launchProfiles,          (void *)&launchProfiles);
    Select(ID_activeProfile,           (void *)&activeProfile);
}

// ****************************************************************************
// Method: MachineProfile::CreateSubAttributeGroup
//
// Purpose:
//   This class contains information about a host for a remote VisIt engine.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

AttributeGroup *
MachineProfile::CreateSubAttributeGroup(int)
{
    return new LaunchProfile;
}

///////////////////////////////////////////////////////////////////////////////
// Persistence methods
///////////////////////////////////////////////////////////////////////////////

// ****************************************************************************
// Method: MachineProfile::CreateNode
//
// Purpose:
//   This method creates a DataNode representation of the object so it can
//   be saved to a config file.
//
//   This differs from the auto-generated one in the following ways:
//    - it checks to see if something is selected when saving instead
//      of checking to see if it differs from the default-constructor version,
//      which lets us select user-set values which differ from system-global
//      ones and save only those fields
//    - it always adds hostNickname, as that's how we identify which
//      host profile is which
//    - we use "completeSave" as the cue as to whether our sub-attribute
//      groups add themselves, overriding forceAdd when descending to them
//    - since host nickname is always saved, we always add to the parent node
//
// Programmer: Jeremy Meredith
// Creation:   April 29, 2010
//
// Modifications:
//   Eric Brugger, Tue Apr 19 14:45:18 PDT 2011
//   Added useGateway and gatewayHost.
//
//   Brad Whitlock, Thu Oct  6 11:20:21 PDT 2011
//   Added maximumNodesValid, maximumNodes, maximumProcessorsValid, maximumProcessors
//
//   Brad Whitlock, Tue Jun  5 12:04:03 PDT 2012
//   Added sshCommand, sshCommandSpecified.
//
//   Brad Whitlock, Mon Aug 20 13:50:28 PDT 2012
//   Always save the host and hostAliases because without them those fields can
//   end up being populated by the local machine name. That can cause an
//   unintended host profile match where the mdserver will fail to launch.
//
// ****************************************************************************

bool
MachineProfile::CreateNode(DataNode *parentNode,
                           bool completeSave, bool forceAdd)
{
    if(parentNode == 0)
        return false;

    // Create a node for MachineProfile.
    DataNode *node = new DataNode("MachineProfile");

    node->AddNode(new DataNode("hostNickname", hostNickname));
    node->AddNode(new DataNode("host", host));

    if(completeSave || IsSelected(ID_userName))
        node->AddNode(new DataNode("userName", userName));

    node->AddNode(new DataNode("hostAliases", hostAliases));

    if(completeSave || IsSelected(ID_directory))
        node->AddNode(new DataNode("directory", directory));

    if(completeSave || IsSelected(ID_shareOneBatchJob))
        node->AddNode(new DataNode("shareOneBatchJob", shareOneBatchJob));

    if(completeSave || IsSelected(ID_sshPortSpecified))
        node->AddNode(new DataNode("sshPortSpecified", sshPortSpecified));

    if(completeSave || IsSelected(ID_sshPort))
        node->AddNode(new DataNode("sshPort", sshPort));

    if(completeSave || IsSelected(ID_sshCommandSpecified))
        node->AddNode(new DataNode("sshCommandSpecified", sshCommandSpecified));

    if(completeSave || IsSelected(ID_sshCommand))
        node->AddNode(new DataNode("sshCommand", sshCommand));

    if(completeSave || IsSelected(ID_useGateway))
        node->AddNode(new DataNode("useGateway", useGateway));

    if(completeSave || IsSelected(ID_gatewayHost))
        node->AddNode(new DataNode("gatewayHost", gatewayHost));

    if(completeSave || IsSelected(ID_clientHostDetermination))
        node->AddNode(new DataNode("clientHostDetermination", ClientHostDetermination_ToString(clientHostDetermination)));

    if(completeSave || IsSelected(ID_manualClientHostName))
        node->AddNode(new DataNode("manualClientHostName", manualClientHostName));

    if(completeSave || IsSelected(ID_tunnelSSH))
        node->AddNode(new DataNode("tunnelSSH", tunnelSSH));

    if(completeSave || IsSelected(ID_maximumNodesValid))
        node->AddNode(new DataNode("maximumNodesValid", maximumNodesValid));

    if(completeSave || IsSelected(ID_maximumNodes))
        node->AddNode(new DataNode("maximumNodes", maximumNodes));

    if(completeSave || IsSelected(ID_maximumProcessorsValid))
        node->AddNode(new DataNode("maximumProcessorsValid", maximumProcessorsValid));

    if(completeSave || IsSelected(ID_maximumProcessors))
        node->AddNode(new DataNode("maximumProcessors", maximumProcessors));

    for(size_t i = 0; i < launchProfiles.size(); ++i)
        launchProfiles[i]->CreateNode(node, completeSave,
                     completeSave); // (only force an add for a complete save)

    if(completeSave || IsSelected(ID_activeProfile))
        node->AddNode(new DataNode("activeProfile", activeProfile));

    // Add the node to the parent node.
    parentNode->AddNode(node);
    return true;
}
// ****************************************************************************
// Method: MachineProfile::SetFromNode
//
// Purpose:
//   This method sets attributes in this object from values in a DataNode representation of the object.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//   Jeremy Meredith, Wed Apr 28 17:26:30 EDT 2010
//   For the launch profiles, override old values instead of clearing them.
//
//   Eric Brugger, Tue Apr 19 14:45:18 PDT 2011
//   Added useGateway and gatewayHost.
//
//   Brad Whitlock, Thu Oct  6 11:20:21 PDT 2011
//   Added maximumNodesValid, maximumNodes, maximumProcessorsValid, maximumProcessors
//
//   Brad Whitlock, Tue Jun  5 12:04:03 PDT 2012
//   Added sshCommand, sshCommandSpecified.
//
// ****************************************************************************

void
MachineProfile::SetFromNode(DataNode *parentNode)
{
    if(parentNode == 0)
        return;

    DataNode *searchNode = parentNode->GetNode("MachineProfile");
    if(searchNode == 0)
        return;

    DataNode *node;
    DataNode **children;
    if((node = searchNode->GetNode("host")) != 0)
        SetHost(node->AsString());
    if((node = searchNode->GetNode("userName")) != 0)
        SetUserName(node->AsString());
    if((node = searchNode->GetNode("hostAliases")) != 0)
        SetHostAliases(node->AsString());
    if((node = searchNode->GetNode("hostNickname")) != 0)
        SetHostNickname(node->AsString());
    if((node = searchNode->GetNode("directory")) != 0)
        SetDirectory(node->AsString());
    if((node = searchNode->GetNode("shareOneBatchJob")) != 0)
        SetShareOneBatchJob(node->AsBool());
    if((node = searchNode->GetNode("sshPortSpecified")) != 0)
        SetSshPortSpecified(node->AsBool());
    if((node = searchNode->GetNode("sshPort")) != 0)
        SetSshPort(node->AsInt());
    if((node = searchNode->GetNode("sshCommandSpecified")) != 0)
        SetSshCommandSpecified(node->AsBool());
    if((node = searchNode->GetNode("sshCommand")) != 0)
        SetSshCommand(node->AsStringVector());
    if((node = searchNode->GetNode("useGateway")) != 0)
        SetUseGateway(node->AsBool());
    if((node = searchNode->GetNode("gatewayHost")) != 0)
        SetGatewayHost(node->AsString());
    if((node = searchNode->GetNode("activeProfile")) != 0)
        SetActiveProfile(node->AsInt());
    if((node = searchNode->GetNode("clientHostDetermination")) != 0)
    {
        // Allow enums to be int or string in the config file
        if(node->GetNodeType() == INT_NODE)
        {
            int ival = node->AsInt();
            if(ival >= 0 && ival < 3)
                SetClientHostDetermination(ClientHostDetermination(ival));
        }
        else if(node->GetNodeType() == STRING_NODE)
        {
            ClientHostDetermination value;
            if(ClientHostDetermination_FromString(node->AsString(), value))
                SetClientHostDetermination(value);
        }
    }
    if((node = searchNode->GetNode("manualClientHostName")) != 0)
        SetManualClientHostName(node->AsString());
    if((node = searchNode->GetNode("tunnelSSH")) != 0)
        SetTunnelSSH(node->AsBool());
    if((node = searchNode->GetNode("maximumNodesValid")) != 0)
        SetMaximumNodesValid(node->AsBool());
    if((node = searchNode->GetNode("maximumNodes")) != 0)
    {
        int ival = node->AsInt();
        if(ival > 0)
            SetMaximumNodes(ival);
    }
    if((node = searchNode->GetNode("maximumProcessorsValid")) != 0)
        SetMaximumProcessorsValid(node->AsBool());
    if((node = searchNode->GetNode("maximumProcessors")) != 0)
    {
        int ival = node->AsInt();
        if(ival > 0)
            SetMaximumProcessors(ival);
    }

    // Go through all of the children
    children = searchNode->GetChildren();
    if(children != 0)
    {
        for(int i = 0; i < searchNode->GetNumChildren(); ++i)
        {
            if(children[i]->GetKey() == std::string("LaunchProfile"))
            {
                DataNode *nameNode = children[i]->GetNode("profileName");
                if (!nameNode)
                {
                    // we don't have a name for this launch profile, so we
                    // don't know what to do with it; skip it
                    continue;
                }
                std::string name = nameNode->AsString();
                bool found = false;
                for (int j=0; j<GetNumLaunchProfiles(); j++)
                {
                    LaunchProfile &lp = GetLaunchProfiles(j);
                    if (lp.GetProfileName() == name)
                    {
                        // it matches one already existing...
                        // override any old values with the new ones
                        lp.SetFromNode(children[i]);
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    // didn't find a pre-existing launch profile with
                    // the same name, so just add it to the list.
                    LaunchProfile temp;
                    temp.SetFromNode(children[i]);
                    AddLaunchProfiles(temp);
                }
            }
        }
    }

    // Make sure we didn't get a bad profile index
    if (GetActiveProfile() >= GetNumLaunchProfiles())
        SetActiveProfile(GetNumLaunchProfiles() > 0 ? 0 : -1);
}
///////////////////////////////////////////////////////////////////////////////
// Set property methods
///////////////////////////////////////////////////////////////////////////////

void
MachineProfile::SetHost(const std::string &host_)
{
    host = host_;
    Select(ID_host, (void *)&host);
}

void
MachineProfile::SetUserName(const std::string &userName_)
{
    userName = userName_;
    Select(ID_userName, (void *)&userName);
}

void
MachineProfile::SetPassword(const std::string &password_)
{
    password = password_;
    Select(ID_password, (void *)&password);
}

void
MachineProfile::SetHostAliases(const std::string &hostAliases_)
{
    hostAliases = hostAliases_;
    Select(ID_hostAliases, (void *)&hostAliases);
}

void
MachineProfile::SetHostNickname(const std::string &hostNickname_)
{
    hostNickname = hostNickname_;
    Select(ID_hostNickname, (void *)&hostNickname);
}

void
MachineProfile::SetDirectory(const std::string &directory_)
{
    directory = directory_;
    Select(ID_directory, (void *)&directory);
}

void
MachineProfile::SetShareOneBatchJob(bool shareOneBatchJob_)
{
    shareOneBatchJob = shareOneBatchJob_;
    Select(ID_shareOneBatchJob, (void *)&shareOneBatchJob);
}

void
MachineProfile::SetSshPortSpecified(bool sshPortSpecified_)
{
    sshPortSpecified = sshPortSpecified_;
    Select(ID_sshPortSpecified, (void *)&sshPortSpecified);
}

void
MachineProfile::SetSshPort(int sshPort_)
{
    sshPort = sshPort_;
    Select(ID_sshPort, (void *)&sshPort);
}

void
MachineProfile::SetSshCommandSpecified(bool sshCommandSpecified_)
{
    sshCommandSpecified = sshCommandSpecified_;
    Select(ID_sshCommandSpecified, (void *)&sshCommandSpecified);
}

void
MachineProfile::SetSshCommand(const stringVector &sshCommand_)
{
    sshCommand = sshCommand_;
    Select(ID_sshCommand, (void *)&sshCommand);
}

void
MachineProfile::SetUseGateway(bool useGateway_)
{
    useGateway = useGateway_;
    Select(ID_useGateway, (void *)&useGateway);
}

void
MachineProfile::SetGatewayHost(const std::string &gatewayHost_)
{
    gatewayHost = gatewayHost_;
    Select(ID_gatewayHost, (void *)&gatewayHost);
}

void
MachineProfile::SetClientHostDetermination(MachineProfile::ClientHostDetermination clientHostDetermination_)
{
    clientHostDetermination = clientHostDetermination_;
    Select(ID_clientHostDetermination, (void *)&clientHostDetermination);
}

void
MachineProfile::SetManualClientHostName(const std::string &manualClientHostName_)
{
    manualClientHostName = manualClientHostName_;
    Select(ID_manualClientHostName, (void *)&manualClientHostName);
}

void
MachineProfile::SetTunnelSSH(bool tunnelSSH_)
{
    tunnelSSH = tunnelSSH_;
    Select(ID_tunnelSSH, (void *)&tunnelSSH);
}

void
MachineProfile::SetMaximumNodesValid(bool maximumNodesValid_)
{
    maximumNodesValid = maximumNodesValid_;
    Select(ID_maximumNodesValid, (void *)&maximumNodesValid);
}

void
MachineProfile::SetMaximumNodes(int nnodes)
{
    maximumNodes = nnodes;
    Select(ID_maximumNodes, (void *)&maximumNodes);
    if(maximumNodesValid)
    {
        // Make sure that no profiles have larger #nodes.
        bool changed = false;
        for (int i=0; i<GetNumLaunchProfiles(); i++)
        {
            LaunchProfile &lp = GetLaunchProfiles(i);
            lp.SelectAll();
            if (lp.GetNumNodesSet() && lp.GetNumNodes() > nnodes)
            {
                lp.SetNumNodes(nnodes);
                changed = true;
            }
        }
        if(changed)
            SelectLaunchProfiles();
    }
}

void
MachineProfile::SetMaximumProcessorsValid(bool maximumProcessorsValid_)
{
    maximumProcessorsValid = maximumProcessorsValid_;
    Select(ID_maximumProcessorsValid, (void *)&maximumProcessorsValid);
}

void
MachineProfile::SetMaximumProcessors(int nprocs)
{
    maximumProcessors = nprocs;
    Select(ID_maximumProcessors, (void *)&maximumProcessors);
    if(maximumProcessorsValid)
    {
        // Make sure that no profiles have larger #processors.
        bool changed = false;
        for (int i=0; i<GetNumLaunchProfiles(); i++)
        {
            LaunchProfile &lp = GetLaunchProfiles(i);
            lp.SelectAll();
            if (lp.GetNumProcessors() > nprocs)
            {
                lp.SetNumProcessors(nprocs);
                changed = true;
            }
        }
        if(changed)
            SelectLaunchProfiles();
    }
}

void
MachineProfile::SetActiveProfile(int activeProfile_)
{
    activeProfile = activeProfile_;
    Select(ID_activeProfile, (void *)&activeProfile);
}

///////////////////////////////////////////////////////////////////////////////
// Get property methods
///////////////////////////////////////////////////////////////////////////////

const std::string &
MachineProfile::GetHost() const
{
    return host;
}

std::string &
MachineProfile::GetHost()
{
    return host;
}

const std::string &
MachineProfile::GetUserName() const
{
    return userName;
}

std::string &
MachineProfile::GetUserName()
{
    return userName;
}

const std::string &
MachineProfile::GetPassword() const
{
    return password;
}

std::string &
MachineProfile::GetPassword()
{
    return password;
}

const std::string &
MachineProfile::GetHostAliases() const
{
    return hostAliases;
}

std::string &
MachineProfile::GetHostAliases()
{
    return hostAliases;
}

const std::string &
MachineProfile::GetHostNickname() const
{
    return hostNickname;
}

std::string &
MachineProfile::GetHostNickname()
{
    return hostNickname;
}

const std::string &
MachineProfile::GetDirectory() const
{
    return directory;
}

std::string &
MachineProfile::GetDirectory()
{
    return directory;
}

bool
MachineProfile::GetShareOneBatchJob() const
{
    return shareOneBatchJob;
}

bool
MachineProfile::GetSshPortSpecified() const
{
    return sshPortSpecified;
}

int
MachineProfile::GetSshPort() const
{
    return sshPort;
}

bool
MachineProfile::GetSshCommandSpecified() const
{
    return sshCommandSpecified;
}

const stringVector &
MachineProfile::GetSshCommand() const
{
    return sshCommand;
}

stringVector &
MachineProfile::GetSshCommand()
{
    return sshCommand;
}

bool
MachineProfile::GetUseGateway() const
{
    return useGateway;
}

const std::string &
MachineProfile::GetGatewayHost() const
{
    return gatewayHost;
}

std::string &
MachineProfile::GetGatewayHost()
{
    return gatewayHost;
}

MachineProfile::ClientHostDetermination
MachineProfile::GetClientHostDetermination() const
{
    return ClientHostDetermination(clientHostDetermination);
}

const std::string &
MachineProfile::GetManualClientHostName() const
{
    return manualClientHostName;
}

std::string &
MachineProfile::GetManualClientHostName()
{
    return manualClientHostName;
}

bool
MachineProfile::GetTunnelSSH() const
{
    return tunnelSSH;
}

bool
MachineProfile::GetMaximumNodesValid() const
{
    return maximumNodesValid;
}

int
MachineProfile::GetMaximumNodes() const
{
    return maximumNodes;
}

bool
MachineProfile::GetMaximumProcessorsValid() const
{
    return maximumProcessorsValid;
}

int
MachineProfile::GetMaximumProcessors() const
{
    return maximumProcessors;
}

const AttributeGroupVector &
MachineProfile::GetLaunchProfiles() const
{
    return launchProfiles;
}

AttributeGroupVector &
MachineProfile::GetLaunchProfiles()
{
    return launchProfiles;
}

int
MachineProfile::GetActiveProfile() const
{
    return activeProfile;
}

///////////////////////////////////////////////////////////////////////////////
// Select property methods
///////////////////////////////////////////////////////////////////////////////

void
MachineProfile::SelectHost()
{
    Select(ID_host, (void *)&host);
}

void
MachineProfile::SelectUserName()
{
    Select(ID_userName, (void *)&userName);
}

void
MachineProfile::SelectPassword()
{
    Select(ID_password, (void *)&password);
}

void
MachineProfile::SelectHostAliases()
{
    Select(ID_hostAliases, (void *)&hostAliases);
}

void
MachineProfile::SelectHostNickname()
{
    Select(ID_hostNickname, (void *)&hostNickname);
}

void
MachineProfile::SelectDirectory()
{
    Select(ID_directory, (void *)&directory);
}

void
MachineProfile::SelectSshCommand()
{
    Select(ID_sshCommand, (void *)&sshCommand);
}

void
MachineProfile::SelectGatewayHost()
{
    Select(ID_gatewayHost, (void *)&gatewayHost);
}

void
MachineProfile::SelectManualClientHostName()
{
    Select(ID_manualClientHostName, (void *)&manualClientHostName);
}

void
MachineProfile::SelectLaunchProfiles()
{
    Select(ID_launchProfiles, (void *)&launchProfiles);
}

///////////////////////////////////////////////////////////////////////////////
// AttributeGroupVector convenience methods.
///////////////////////////////////////////////////////////////////////////////

// ****************************************************************************
// Method: MachineProfile::AddLaunchProfiles
//
// Purpose:
//   This class contains information about a host for a remote VisIt engine.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

void
MachineProfile::AddLaunchProfiles(const LaunchProfile &obj)
{
    LaunchProfile *newLaunchProfile = new LaunchProfile(obj);
    launchProfiles.push_back(newLaunchProfile);

    // Indicate that things have changed by selecting it.
    Select(ID_launchProfiles, (void *)&launchProfiles);
}

// ****************************************************************************
// Method: MachineProfile::ClearLaunchProfiles
//
// Purpose:
//   This class contains information about a host for a remote VisIt engine.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

void
MachineProfile::ClearLaunchProfiles()
{
    AttributeGroupVector::iterator pos;

    for(pos = launchProfiles.begin(); pos != launchProfiles.end(); ++pos)
        delete *pos;
    launchProfiles.clear();

    // Indicate that things have changed by selecting the list.
    Select(ID_launchProfiles, (void *)&launchProfiles);
}

// ****************************************************************************
// Method: MachineProfile::RemoveLaunchProfiles
//
// Purpose:
//   This class contains information about a host for a remote VisIt engine.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

void
MachineProfile::RemoveLaunchProfiles(int index)
{
    AttributeGroupVector::iterator pos = launchProfiles.begin();

    // Iterate through the vector "index" times.
    for(int i = 0; i < index; ++i)
        if(pos != launchProfiles.end()) ++pos;

    // If pos is still a valid iterator, remove that element.
    if(pos != launchProfiles.end())
    {
        delete *pos;
        launchProfiles.erase(pos);
    }

    // Indicate that things have changed by selecting the list.
    Select(ID_launchProfiles, (void *)&launchProfiles);
}

// ****************************************************************************
// Method: MachineProfile::GetNumLaunchProfiles
//
// Purpose:
//   This class contains information about a host for a remote VisIt engine.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

int
MachineProfile::GetNumLaunchProfiles() const
{
    return (int)launchProfiles.size();
}

// ****************************************************************************
// Method: MachineProfile::GetLaunchProfiles
//
// Purpose:
//   This class contains information about a host for a remote VisIt engine.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

LaunchProfile &
MachineProfile::GetLaunchProfiles(int i)
{
    return *((LaunchProfile *)launchProfiles[i]);
}

// ****************************************************************************
// Method: MachineProfile::GetLaunchProfiles
//
// Purpose:
//   This class contains information about a host for a remote VisIt engine.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

const LaunchProfile &
MachineProfile::GetLaunchProfiles(int i) const
{
    return *((LaunchProfile *)launchProfiles[i]);
}

// ****************************************************************************
// Method: MachineProfile::operator []
//
// Purpose:
//   This class contains information about a host for a remote VisIt engine.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

LaunchProfile &
MachineProfile::operator [] (int i)
{
    return *((LaunchProfile *)launchProfiles[i]);
}

// ****************************************************************************
// Method: MachineProfile::operator []
//
// Purpose:
//   This class contains information about a host for a remote VisIt engine.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

const LaunchProfile &
MachineProfile::operator [] (int i) const
{
    return *((LaunchProfile *)launchProfiles[i]);
}

///////////////////////////////////////////////////////////////////////////////
// Keyframing methods
///////////////////////////////////////////////////////////////////////////////

// ****************************************************************************
// Method: MachineProfile::GetFieldName
//
// Purpose:
//   This method returns the name of a field given its index.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

std::string
MachineProfile::GetFieldName(int index) const
{
    switch (index)
    {
    case ID_host:                    return "host";
    case ID_userName:                return "userName";
    case ID_password:                return "password";
    case ID_hostAliases:             return "hostAliases";
    case ID_hostNickname:            return "hostNickname";
    case ID_directory:               return "directory";
    case ID_shareOneBatchJob:        return "shareOneBatchJob";
    case ID_sshPortSpecified:        return "sshPortSpecified";
    case ID_sshPort:                 return "sshPort";
    case ID_sshCommandSpecified:     return "sshCommandSpecified";
    case ID_sshCommand:              return "sshCommand";
    case ID_useGateway:              return "useGateway";
    case ID_gatewayHost:             return "gatewayHost";
    case ID_clientHostDetermination: return "clientHostDetermination";
    case ID_manualClientHostName:    return "manualClientHostName";
    case ID_tunnelSSH:               return "tunnelSSH";
    case ID_maximumNodesValid:       return "maximumNodesValid";
    case ID_maximumNodes:            return "maximumNodes";
    case ID_maximumProcessorsValid:  return "maximumProcessorsValid";
    case ID_maximumProcessors:       return "maximumProcessors";
    case ID_launchProfiles:          return "launchProfiles";
    case ID_activeProfile:           return "activeProfile";
    default:  return "invalid index";
    }
}

// ****************************************************************************
// Method: MachineProfile::GetFieldType
//
// Purpose:
//   This method returns the type of a field given its index.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

AttributeGroup::FieldType
MachineProfile::GetFieldType(int index) const
{
    switch (index)
    {
    case ID_host:                    return FieldType_string;
    case ID_userName:                return FieldType_string;
    case ID_password:                return FieldType_string;
    case ID_hostAliases:             return FieldType_string;
    case ID_hostNickname:            return FieldType_string;
    case ID_directory:               return FieldType_string;
    case ID_shareOneBatchJob:        return FieldType_bool;
    case ID_sshPortSpecified:        return FieldType_bool;
    case ID_sshPort:                 return FieldType_int;
    case ID_sshCommandSpecified:     return FieldType_bool;
    case ID_sshCommand:              return FieldType_stringVector;
    case ID_useGateway:              return FieldType_bool;
    case ID_gatewayHost:             return FieldType_string;
    case ID_clientHostDetermination: return FieldType_enum;
    case ID_manualClientHostName:    return FieldType_string;
    case ID_tunnelSSH:               return FieldType_bool;
    case ID_maximumNodesValid:       return FieldType_bool;
    case ID_maximumNodes:            return FieldType_int;
    case ID_maximumProcessorsValid:  return FieldType_bool;
    case ID_maximumProcessors:       return FieldType_int;
    case ID_launchProfiles:          return FieldType_attVector;
    case ID_activeProfile:           return FieldType_int;
    default:  return FieldType_unknown;
    }
}

// ****************************************************************************
// Method: MachineProfile::GetFieldTypeName
//
// Purpose:
//   This method returns the name of a field type given its index.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

std::string
MachineProfile::GetFieldTypeName(int index) const
{
    switch (index)
    {
    case ID_host:                    return "string";
    case ID_userName:                return "string";
    case ID_password:                return "string";
    case ID_hostAliases:             return "string";
    case ID_hostNickname:            return "string";
    case ID_directory:               return "string";
    case ID_shareOneBatchJob:        return "bool";
    case ID_sshPortSpecified:        return "bool";
    case ID_sshPort:                 return "int";
    case ID_sshCommandSpecified:     return "bool";
    case ID_sshCommand:              return "stringVector";
    case ID_useGateway:              return "bool";
    case ID_gatewayHost:             return "string";
    case ID_clientHostDetermination: return "enum";
    case ID_manualClientHostName:    return "string";
    case ID_tunnelSSH:               return "bool";
    case ID_maximumNodesValid:       return "bool";
    case ID_maximumNodes:            return "int";
    case ID_maximumProcessorsValid:  return "bool";
    case ID_maximumProcessors:       return "int";
    case ID_launchProfiles:          return "attVector";
    case ID_activeProfile:           return "int";
    default:  return "invalid index";
    }
}

// ****************************************************************************
// Method: MachineProfile::FieldsEqual
//
// Purpose:
//   This method compares two fields and return true if they are equal.
//
// Note:       Autogenerated by xml2atts.
//
// Programmer: xml2atts
// Creation:   omitted
//
// Modifications:
//
// ****************************************************************************

bool
MachineProfile::FieldsEqual(int index_, const AttributeGroup *rhs) const
{
    const MachineProfile &obj = *((const MachineProfile*)rhs);
    bool retval = false;
    switch (index_)
    {
    case ID_host:
        {  // new scope
        retval = (host == obj.host);
        }
        break;
    case ID_userName:
        {  // new scope
        retval = (userName == obj.userName);
        }
        break;
    case ID_password:
        {  // new scope
        retval = (password == obj.password);
        }
        break;
    case ID_hostAliases:
        {  // new scope
        retval = (hostAliases == obj.hostAliases);
        }
        break;
    case ID_hostNickname:
        {  // new scope
        retval = (hostNickname == obj.hostNickname);
        }
        break;
    case ID_directory:
        {  // new scope
        retval = (directory == obj.directory);
        }
        break;
    case ID_shareOneBatchJob:
        {  // new scope
        retval = (shareOneBatchJob == obj.shareOneBatchJob);
        }
        break;
    case ID_sshPortSpecified:
        {  // new scope
        retval = (sshPortSpecified == obj.sshPortSpecified);
        }
        break;
    case ID_sshPort:
        {  // new scope
        retval = (sshPort == obj.sshPort);
        }
        break;
    case ID_sshCommandSpecified:
        {  // new scope
        retval = (sshCommandSpecified == obj.sshCommandSpecified);
        }
        break;
    case ID_sshCommand:
        {  // new scope
        retval = (sshCommand == obj.sshCommand);
        }
        break;
    case ID_useGateway:
        {  // new scope
        retval = (useGateway == obj.useGateway);
        }
        break;
    case ID_gatewayHost:
        {  // new scope
        retval = (gatewayHost == obj.gatewayHost);
        }
        break;
    case ID_clientHostDetermination:
        {  // new scope
        retval = (clientHostDetermination == obj.clientHostDetermination);
        }
        break;
    case ID_manualClientHostName:
        {  // new scope
        retval = (manualClientHostName == obj.manualClientHostName);
        }
        break;
    case ID_tunnelSSH:
        {  // new scope
        retval = (tunnelSSH == obj.tunnelSSH);
        }
        break;
    case ID_maximumNodesValid:
        {  // new scope
        retval = (maximumNodesValid == obj.maximumNodesValid);
        }
        break;
    case ID_maximumNodes:
        {  // new scope
        retval = (maximumNodes == obj.maximumNodes);
        }
        break;
    case ID_maximumProcessorsValid:
        {  // new scope
        retval = (maximumProcessorsValid == obj.maximumProcessorsValid);
        }
        break;
    case ID_maximumProcessors:
        {  // new scope
        retval = (maximumProcessors == obj.maximumProcessors);
        }
        break;
    case ID_launchProfiles:
        {  // new scope
        bool launchProfiles_equal = (obj.launchProfiles.size() == launchProfiles.size());
        for(size_t i = 0; (i < launchProfiles.size()) && launchProfiles_equal; ++i)
        {
            // Make references to LaunchProfile from AttributeGroup *.
            const LaunchProfile &launchProfiles1 = *((const LaunchProfile *)(launchProfiles[i]));
            const LaunchProfile &launchProfiles2 = *((const LaunchProfile *)(obj.launchProfiles[i]));
            launchProfiles_equal = (launchProfiles1 == launchProfiles2);
        }

        retval = launchProfiles_equal;
        }
        break;
    case ID_activeProfile:
        {  // new scope
        retval = (activeProfile == obj.activeProfile);
        }
        break;
    default: retval = false;
    }

    return retval;
}

///////////////////////////////////////////////////////////////////////////////
// User-defined methods.
///////////////////////////////////////////////////////////////////////////////

std::string MachineProfile::defaultUserName("notset");

// ****************************************************************************
// Method: MachineProfile::UserName
//
// Purpose:
//   Return the userName. We have to use this instead of GetUserName since that
//   is a macro definition on Windows that changes the name to GetUserNameA.
//
// Programmer: Brad Whitlock
// Creation:   Thu Jun 14 15:56:10 PDT 2012
//
// Modifications:
//
// ****************************************************************************
const std::string &
MachineProfile::UserName() const
{
    return userName;
}

// ****************************************************************************
// Method: MachineProfile::Default
//
// Purpose:
//   Return a basic MachineProfile for the specified host.
//
// Arguments:
//   host : The host where we want to launch.
//
// Programmer: Brad Whitlock
// Creation:   Tue Jun  5 15:00:37 PDT 2012
//
// Modifications:
//
// ****************************************************************************

MachineProfile
MachineProfile::Default(const std::string &host, const std::string &user)
{
    MachineProfile profile;
    std::string h("localhost");
    if(!host.empty())
        h = host;
    profile.SetHost(h);
    if(user.empty())
        profile.SetUserName(defaultUserName);
    else
        profile.SetUserName(user);
    profile.SetHostAliases(h);
    profile.SetHostNickname(h);
    profile.SetClientHostDetermination(MachineProfile::MachineName);
    return profile;
}

// ****************************************************************************
//  Method:  SplitHostPattern
//
//  Purpose:
//    Returns the host name pattern split into strings by whitespace or commas.
//
//  Programmer:  Jeremy Meredith
//  Creation:    February 13, 2002
//
// ****************************************************************************
std::vector<std::string>
MachineProfile::SplitHostPattern(const std::string &host)
{
    std::vector<std::string> vec;
    std::string              name = "";

    for (size_t i=0; i<host.length(); i++)
    {
        if (host[i] == ' '  || host[i] == '\t' || host[i] == ',')
        {
            if (!name.empty())
            {
                vec.push_back(name);
                name = "";
            }
            continue;
        }
        else
        {
            name += host[i];
        }
    }
    if (!name.empty())
    {
        vec.push_back(name);
        name = "";
    }

    return vec;
}

// ****************************************************************************
//  Method:  ProfileMatchesHost
//
//  Purpose:
//    True if a hostname matches the host name pattern in the profile.
//
//  Arguments:
//    h          the hostname to compare with this profile
//
//  Programmer:  Jeremy Meredith
//  Creation:    February 13, 2002
//
//  Modifications:
//    Jeremy Meredith, Mon Apr 14 10:06:34 PDT 2003
//    Added matching of host aliases.
//
// ****************************************************************************
bool
MachineProfile::ProfileMatchesHost(const std::string &h) const
{
    std::vector<std::string> patterns = SplitHostPattern(host);
    bool match = false;
    size_t i;

    // Try to match the actual host name
    for (i = 0; i < patterns.size() && !match; i++)
    {
         match = WildcardStringMatch(patterns[i], h);
    }

    // Now match any aliases
    std::vector<std::string> aliases = SplitHostPattern(hostAliases);
    for (i = 0; i < aliases.size() && !match; i++)
    {
         match = WildcardStringMatch(aliases[i], h);
    }

    return match;
}

// ****************************************************************************
//  Method:  GetShortHostname
//
//  Purpose:
//    Returns a shortened version of the hostname.
//
//  Programmer:  Jeremy Meredith
//  Creation:    February 13, 2002
//
// ****************************************************************************
std::string
MachineProfile::GetShortHostname() const
{
    return GetShortHostname(host);
}

// ****************************************************************************
//  Method:  GetShortHostname
//
//  Purpose:
//    Returns a shortened version of the hostname.
//
//  Programmer:  Jeremy Meredith
//  Creation:    February 13, 2002
//
//  Modifications:
//    Jeremy Meredith, Mon Apr 14 14:35:07 PDT 2003
//    Added ability to append a common suffix from patterns.
//
//    Jeremy Meredith, Fri Nov 14 10:37:59 PST 2003
//    Removed the suffix for now, and stop at the first dot.
//
// ****************************************************************************
std::string
MachineProfile::GetShortHostname(const std::string &host)
{
    std::vector<std::string> patterns = SplitHostPattern(host);
    std::string              prefix = "";
    std::string              suffix = "";
    std::string              shortname;

    if (patterns.empty())
        return "";

    // find the minimum length of any string
    size_t l = patterns[0].length();
    for (size_t i = 1; i < patterns.size(); i++)
    {
        if (patterns[i].length() < l)
            l = patterns[i].length();
    }

    // find a common prefix
    for (size_t p = 0; p < l; p++)
    {
        char c = patterns[0][p];
        for (size_t i = 1; i < patterns.size() && c != '\0'; i++)
        {
            if (patterns[i][p] != c)
                c = '\0';
        }
        if (c=='\0' || c=='.')
            break;
        if (c != '*' && c != '?')
            prefix += c;
    }

    // find a common suffix, too
    for (size_t s = 0; s < l - prefix.length() - 1 && patterns.size() > 1; s++)
    {
        char c = patterns[0][l-1-s];
        for (size_t i = 1; i < patterns.size() && c != '\0'; i++)
        {
            if (patterns[i][l-1-s] != c)
                c = '\0';
        }
        if (!c)
            break;
        if (c != '*' && c != '?')
            suffix = c + suffix;
    }

    // combine the short name
    //shortname = prefix + suffix;
    shortname = prefix;
    if (prefix.empty())
        return patterns[0];
    else
        return shortname;
}

// ****************************************************************************
//  Method:  GetDefaultUserName
//
//  Purpose:
//    Returns the default user name.
//
//  Programmer:  Brad Whitlock
//  Creation:    Thu Apr 11 15:13:46 PST 2002
//
// ****************************************************************************

const std::string &
MachineProfile::GetDefaultUserName()
{
    return defaultUserName;
}

// ****************************************************************************
//  Method:  SetDefaultUserName
//
//  Purpose:
//    Returns the default user name.
//
//  Programmer:  Brad Whitlock
//  Creation:    Thu Apr 11 15:13:46 PST 2002
//
// ****************************************************************************

void
MachineProfile::SetDefaultUserName(const std::string &n)
{
    defaultUserName = n;
}

LaunchProfile *
MachineProfile::GetActiveLaunchProfile() const
{
    if (activeProfile<0 || (size_t)activeProfile>=launchProfiles.size())
        return NULL;

    return (LaunchProfile*)launchProfiles[activeProfile];
}

// ****************************************************************************
// Method:  MachineProfile::SelectOnlyDifferingFields
//
// Purpose:
//   Select only fields which differ from a compared attribute.
//
// Arguments:
//   other      the profile to compare against
//
// Programmer:  Jeremy Meredith
// Creation:    April 29, 2010
//
// Modifications:
//   Eric Brugger, Tue Apr 19 14:45:18 PDT 2011
//   Added useGateway and gatewayHost.
//
//   Brad Whitlock, Thu Oct  6 11:20:21 PDT 2011
//   Added maximumNodesValid, maximumNodes, maximumProcessorsValid, maximumProcessors
//
//   Brad Whitlock, Tue Jun  5 12:04:56 PDT 2012
//   I added sshCommand, sshCommandSpecified.
//
// ****************************************************************************

void
MachineProfile::SelectOnlyDifferingFields(MachineProfile &other)
{
    UnSelectAll();

    if (host != other.host)
        Select(ID_host,                    (void *)&host);
    if (userName != other.userName)
        Select(ID_userName,                (void *)&userName);
    if (hostAliases != other.hostAliases)
        Select(ID_hostAliases,             (void *)&hostAliases);
    if (hostNickname != other.hostNickname)
        Select(ID_hostNickname,            (void *)&hostNickname);
    if (directory != other.directory)
        Select(ID_directory,               (void *)&directory);
    if (shareOneBatchJob != other.shareOneBatchJob)
        Select(ID_shareOneBatchJob,        (void *)&shareOneBatchJob);
    if (sshPortSpecified != other.sshPortSpecified)
        Select(ID_sshPortSpecified,        (void *)&sshPortSpecified);
    if (sshPort != other.sshPort)
        Select(ID_sshPort,                 (void *)&sshPort);
    if (sshCommandSpecified != other.sshCommandSpecified)
        Select(ID_sshCommandSpecified,        (void *)&sshCommandSpecified);
    if (sshCommand != other.sshCommand)
        Select(ID_sshCommand,                 (void *)&sshCommand);
    if (useGateway != other.useGateway)
        Select(ID_useGateway,              (void *)&useGateway);
    if (gatewayHost != other.gatewayHost)
        Select(ID_gatewayHost,             (void *)&gatewayHost);
    if (clientHostDetermination != other.clientHostDetermination)
        Select(ID_clientHostDetermination, (void *)&clientHostDetermination);
    if (manualClientHostName != other.manualClientHostName)
        Select(ID_manualClientHostName,    (void *)&manualClientHostName);
    if (tunnelSSH != other.tunnelSSH)
        Select(ID_tunnelSSH,               (void *)&tunnelSSH);
    if (activeProfile != other.activeProfile)
        Select(ID_activeProfile,           (void *)&activeProfile);
    if(maximumNodesValid != other.maximumNodesValid)
        Select(ID_maximumNodesValid,       (void *)&maximumNodesValid);
    if(maximumNodes != other.maximumNodes)
        Select(ID_maximumNodes,            (void *)&maximumNodes);
    if(maximumProcessorsValid != other.maximumProcessorsValid)
        Select(ID_maximumProcessorsValid,  (void *)&maximumProcessorsValid);
    if(maximumProcessors != other.maximumProcessors)
        Select(ID_maximumProcessors,       (void *)&maximumProcessors);

    for (int i=0; i<GetNumLaunchProfiles(); i++)
    {
        LaunchProfile &lp = GetLaunchProfiles(i);
        lp.SelectAll();
        for (int j=0; j<other.GetNumLaunchProfiles(); j++)
        {
            LaunchProfile &otherlp = other.GetLaunchProfiles(j);
            if (lp.GetProfileName() == otherlp.GetProfileName())
            {
                lp.SelectOnlyDifferingFields(otherlp);
                break;
            }
        }
    }
}

// ****************************************************************************
// Method: MachineProfile::Print
//
// Purpose:
//   Print the MachineProfile to a stream.
//
// Arguments:
//   out : The output stream.
//
// Programmer: Brad Whitlock
// Creation:   Tue Jun  5 15:00:37 PDT 2012
//
// Modifications:
//
// ****************************************************************************

void
MachineProfile::Print(ostream &out) const
{
    out << "hostNickName=" << GetHostNickname() << endl;
    out << "host=" << GetHost() << endl;
    out << "username=" << GetUserName() << endl;
    out << "hostAliases=" << GetHostAliases() << endl;
    out << "directory=" << GetDirectory() << endl;
    out << "shareOneBatchJob=" << (GetShareOneBatchJob()?"true":"false") << endl;
    out << "tunnelSSH=" << (GetTunnelSSH()?"true":"false") << endl;
    out << "sshPortSpecified=" << (GetSshPortSpecified()?"true":"false") << endl;
    out << "sshPort=" << GetSshPort() << endl;
    out << "sshCommandSpecified=" << (GetSshCommandSpecified()?"true":"false") << endl;
    out << "sshCommand={";
    size_t len = GetSshCommand().size();
    for(size_t i = 0; i < len; ++i)
    {
        out << GetSshCommand()[i];
        if(i < len-1)
            out << ", ";
    }
    out << "}" << endl;
    out << "useGateway=" << (GetUseGateway()?"true":"false") << endl;
    out << "gatewayHost=" << GetGatewayHost() << endl;
    out << "clientHostDetermination=" << ClientHostDetermination_ToString(GetClientHostDetermination()) << endl;
    out << "manualClientHostName=" << GetManualClientHostName() << endl;
    out << "maximumNodesValid=" << (GetMaximumNodesValid()?"true":"false") << endl;
    out << "maximumNodes=" << GetMaximumNodes() << endl;
    out << "maximumProcessorsValid=" << (GetMaximumProcessorsValid()?"true":"false") << endl;
    out << "maximumProcessors=" << GetMaximumProcessors() << endl;

    // Don't print launch profiles...
}

